﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Groovy_IM.Protocols.AIM
{
    public class PacketBuilder
    {
        public FLAPSocket ActivateSSI()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 19;
            packet.Data[3] = 7;
            packet.Data[9] = 7;

            return packet;
        }

        public FLAPSocket ConnectPacket()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.Connect;

            packet.Data = new byte[4];

            packet.Data[3] = 0x01;

            return packet;
        }

        public FLAPSocket FlapAlive()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.KeepAlive;

            List<byte> TLVs = new List<byte>();

            return packet;
        }

        public FLAPSocket FlapCookie(byte[] Cookie)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.Connect;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x01 });

            TLVs.AddRange(Tools.MakeTLV(0x06, Cookie));

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket Login(string Screenname, byte[] Password, byte[] Challenge, bool MobileLogin)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x17, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 });

            TLVs.AddRange(Tools.MakeTLV(0x01, Screenname));

            TLVs.AddRange(Tools.MakeTLV(0x25, AIMClasses.encryptPW(Challenge, Password)));

            TLVs.AddRange(new byte[] { 0x00, 0x4c, 0x00, 0x00 });

            TLVs.AddRange(Tools.MakeTLV(0x03, "Pidgin/2.10.0"));

            TLVs.AddRange(Tools.MakeTLV(0x16, new byte[] { 0x01, 0x09 }));

            TLVs.AddRange(Tools.MakeTLV(0x17, new byte[] { 0x00, 0x05 }));

            TLVs.AddRange(Tools.MakeTLV(0x18, new byte[] { 0x00, 0x01 }));

            TLVs.AddRange(Tools.MakeTLV(0x19, new byte[] { 0x00, 0x00 }));

            TLVs.AddRange(Tools.MakeTLV(0x1a, new byte[] { 0x0b, 0xdc }));

            TLVs.AddRange(Tools.MakeTLV(0x14, new byte[] { 0x00, 0x00, 0x06, 0x0e }));

            TLVs.AddRange(Tools.MakeTLV(0x0f, new byte[] { 0x65, 0x6e }));

            TLVs.AddRange(Tools.MakeTLV(0x0e, new byte[] { 0x75, 0x73 }));

            if (MobileLogin == false)
                TLVs.AddRange(Tools.MakeTLV(0x4a, new byte[] { 1 }));
            else
                TLVs.AddRange(Tools.MakeTLV(0x4a, new byte[] { 129 }));

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket RateAck()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[20];

            packet.Data[1] = 1;

            packet.Data[3] = 8;

            packet.Data[9] = 8;

            packet.Data[11] = 1;

            packet.Data[13] = 2;

            packet.Data[15] = 3;

            packet.Data[17] = 4;

            packet.Data[19] = 5;

            return packet;
        }

        public FLAPSocket RequestBuddyIcon(string Screenname, int AvatarID, byte AvatarFlags, byte[] Hash)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, (byte)Screenname.Length });

            TLVs.AddRange(Encoding.UTF8.GetBytes(Screenname));

            TLVs.AddRange(new byte[] { 0x01, (byte)(AvatarID / 256), (byte)(AvatarID % 256), AvatarFlags, (byte)Hash.Length });

            TLVs.AddRange(Hash);

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket RequestBuddylistPrivacyRights()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 9;
            packet.Data[3] = 2;
            packet.Data[9] = 2;

            return packet;
        }

        public FLAPSocket RequestBuddylistRights()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 3;
            packet.Data[3] = 2;
            packet.Data[9] = 2;

            return packet;
        }

        public FLAPSocket RequestChallenge(string Screenname)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x17, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 });

            TLVs.AddRange(Tools.MakeTLV(0x01, Screenname));

            TLVs.AddRange(Tools.MakeTLV(0x4b, ""));

            TLVs.AddRange(Tools.MakeTLV(0x5a, ""));

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket RequestContactList(bool firstTime)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 19;

            if (firstTime)
            {
                packet.Data[3] = 4;
                packet.Data[9] = 4;
            }
            else
            {
                packet.Data[3] = 7;
                packet.Data[9] = 7;
            }

            return packet;
        }

        public FLAPSocket RequestICBMParamRights()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 4;
            packet.Data[3] = 4;
            packet.Data[9] = 4;

            return packet;
        }

        public FLAPSocket RequestLocationRights()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 2;
            packet.Data[3] = 2;
            packet.Data[9] = 2;

            return packet;
        }

        public FLAPSocket RequestMigration(Queue<byte> Services)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c });

            if (Services.Contains(0x15))
                TLVs.AddRange(new byte[] { 0x00, 0x15 }); //Family Service > Family Version (ICQ)

            if (Services.Contains(0x13))
                TLVs.AddRange(new byte[] { 0x00, 0x13 }); //Family Service > Family Version (SSI / Buddylist)

            if (Services.Contains(0x0b))
                TLVs.AddRange(new byte[] { 0x00, 0x0b }); //Family Service > Family Version (Usage Stats)

            if (Services.Contains(0x0a))
                TLVs.AddRange(new byte[] { 0x00, 0x0a }); //Family Service > Family Version (User Lookup)

            if (Services.Contains(0x09))
                TLVs.AddRange(new byte[] { 0x00, 0x09 }); //Family Service > Family Version (Privacy)

            if (Services.Contains(0x08))
                TLVs.AddRange(new byte[] { 0x00, 0x08 }); //Family Service > Family Version (Popup Service)

            if (Services.Contains(0x04))
                TLVs.AddRange(new byte[] { 0x00, 0x04 }); //Family Service > Family Version (ICBM Service)

            if (Services.Contains(0x03))
                TLVs.AddRange(new byte[] { 0x00, 0x03 }); //Family Service > Family Version (Buddy List Service)

            if (Services.Contains(0x02))
                TLVs.AddRange(new byte[] { 0x00, 0x02 }); //Family Service > Family Version (Location Service)

            if (Services.Contains(0x01))
                TLVs.AddRange(new byte[] { 0x00, 0x01 }); //Family Service > Family Version (Generic Service)

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket RequestOwnInformation()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 1;
            packet.Data[3] = 14;
            packet.Data[9] = 14;

            return packet;
        }

        public FLAPSocket RequestRateLimits()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 1;

            packet.Data[3] = 6;

            packet.Data[9] = 6;

            return packet;
        }

        public FLAPSocket RequestService(ushort ReqID, ushort Type)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[12];

            packet.Data[1] = 1;
            packet.Data[3] = 4;

            Tools.PutWord(packet.Data, 5, ReqID);

            packet.Data[9] = 4;

            Tools.PutWord(packet.Data, 10, Type);

            return packet;
        }

        public FLAPSocket RequestServiceParameters()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            packet.Data = new byte[10];

            packet.Data[1] = 19;
            packet.Data[3] = 2;
            packet.Data[9] = 2;

            return packet;
        }

        public FLAPSocket ServiceReady(Queue<byte> Services)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 });

            if (Services.Contains(0x15))
                TLVs.AddRange(new byte[] { 0x00, 0x15, 0x00, 0x01, 0x01, 0x10, 0x04, 0x7c }); //Family Service > Family Version (ICQ)

            if (Services.Contains(0x13))
                TLVs.AddRange(new byte[] { 0x00, 0x13, 0x00, 0x04, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (SSI / Buddylist)

            if (Services.Contains(0x10))
                TLVs.AddRange(new byte[] { 0x00, 0x10, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (BART)

            if (Services.Contains(0x0b))
                TLVs.AddRange(new byte[] { 0x00, 0x0b, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01 }); //Family Service > Family Version (Usage Stats)

            if (Services.Contains(0x0a))
                TLVs.AddRange(new byte[] { 0x00, 0x0a, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (User Lookup)

            if (Services.Contains(0x09))
                TLVs.AddRange(new byte[] { 0x00, 0x09, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (Privacy)

            if (Services.Contains(0x08))
                TLVs.AddRange(new byte[] { 0x00, 0x08, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01 }); //Family Service > Family Version (Popup Service)

            if (Services.Contains(0x04))
                TLVs.AddRange(new byte[] { 0x00, 0x04, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (ICBM Service)

            if (Services.Contains(0x03))
                TLVs.AddRange(new byte[] { 0x00, 0x03, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (Buddy List Service)

            if (Services.Contains(0x02))
                TLVs.AddRange(new byte[] { 0x00, 0x02, 0x00, 0x01, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (Location Service)

            if (Services.Contains(0x01))
                TLVs.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x03, 0x01, 0x10, 0x06, 0x29 }); //Family Service > Family Version (Generic Service)

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket ServiceVersions(Queue<byte> Services)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17 });

            if (Services.Contains(0x15))
                TLVs.AddRange(new byte[] { 0x00, 0x15, 0x00, 0x01 }); //Family Service > Family Version (ICQ)

            if (Services.Contains(0x13))
                TLVs.AddRange(new byte[] { 0x00, 0x13, 0x00, 0x04 }); //Family Service > Family Version (SSI / Buddylist)

            if (Services.Contains(0x10))
                TLVs.AddRange(new byte[] { 0x00, 0x10, 0x00, 0x01 }); //Family Service > Family Version (BART)

            if (Services.Contains(0x0b))
                TLVs.AddRange(new byte[] { 0x00, 0x0b, 0x00, 0x01 }); //Family Service > Family Version (Usage Stats)

            if (Services.Contains(0x0a))
                TLVs.AddRange(new byte[] { 0x00, 0x0a, 0x00, 0x01 }); //Family Service > Family Version (User Lookup)

            if (Services.Contains(0x09))
                TLVs.AddRange(new byte[] { 0x00, 0x09, 0x00, 0x01 }); //Family Service > Family Version (Privacy)

            if (Services.Contains(0x08))
                TLVs.AddRange(new byte[] { 0x00, 0x08, 0x00, 0x01 }); //Family Service > Family Version (Popup Service)

            if (Services.Contains(0x04))
                TLVs.AddRange(new byte[] { 0x00, 0x04, 0x00, 0x01 }); //Family Service > Family Version (ICBM Service)

            if (Services.Contains(0x03))
                TLVs.AddRange(new byte[] { 0x00, 0x03, 0x00, 0x01 }); //Family Service > Family Version (Buddy List Service)

            if (Services.Contains(0x02))
                TLVs.AddRange(new byte[] { 0x00, 0x02, 0x00, 0x01 }); //Family Service > Family Version (Location Service)

            if (Services.Contains(0x01))
                TLVs.AddRange(new byte[] { 0x00, 0x01, 0x00, 0x03 }); //Family Service > Family Version (Generic Service)

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket SetMyDCInfo(int Type)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0, 1, 0, 30, 0, 0, 0, 0, 0, 30 });

            /*00 1d 00 08 00 02 00 00 00 09 00 00 
            
00 1d 00 08 00 02 00 00 00 09 00 00 

00 0c 00 25 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 50 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
*/

            switch (Type)
            {
                case 0:
                    TLVs.AddRange(Tools.MakeTLV(6, new byte[] { 16, 2, 0, 0 }));
                    TLVs.AddRange(Tools.MakeTLV(29, new byte[] { 0, 2, 0, 0, 0, 9, 0, 0 }));
                    break;
                case 1:
                    TLVs.AddRange(Tools.MakeTLV(29, new byte[] { 0, 2, 0, 0, 0, 9, 0, 0 }));
                    break;
                case 2:
                    TLVs.AddRange(Tools.MakeTLV(12, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
                    break;
            }

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket SetMyICBM()
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0, 4, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0x5b, 0x1b, 0x1f, 0x40, 0x03, 0x84, 0x03, 0xe7, 0x00, 0x00, 0x00, 0x00 });

            //(Channel) 00 00  (Flags) 00 00 05 1b  (Msg) 1f 40 (Sender) 03 84 (Recvr) 03 e7 (Min Msg) 00 00 (Random) 00 00 

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket SetMyInformation(bool SetProfile, string Profile, bool SetAway, string Away, bool SetCapabilities, byte[] Capabilities)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0, 2, 0, 4, 0, 0, 0, 0, 0, 4 });

            if (SetProfile == true)
            {
                TLVs.AddRange(Tools.MakeTLV(0x01, "text/aolrtf; charset=\"us-ascii\""));

                TLVs.AddRange(Tools.MakeTLV(0x02, Profile));
            }

            if (SetAway == true)
            {
                TLVs.AddRange(Tools.MakeTLV(0x03, "text/aolrtf; charset=\"us-ascii\""));

                TLVs.AddRange(Tools.MakeTLV(0x04, Away));
            }

            if (SetCapabilities == true)
                TLVs.AddRange(Tools.MakeTLV(0x05, Capabilities));

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }

        public FLAPSocket SetNickStatus(bool setInvisible, int Invisible, bool setStatus, string Status)
        {
            FLAPSocket packet = new FLAPSocket();

            packet.Channel = FLAPChannel.SNAC;

            List<byte> TLVs = new List<byte>();

            TLVs.AddRange(new byte[] { 0, 1, 0, 30, 0, 0, 0, 0, 0, 30 });

            if (setInvisible == true)
            {
                TLVs.AddRange(Tools.MakeTLV(6, new byte[] { 0, 0, (byte)Invisible, 0 }));
            }

            if (setStatus == true)
            {
                int sLen = Status.Length + 4;

                byte[] sData = new byte[] { 0, 2, 4, (byte)sLen, 0, (byte)Status.Length };

                byte[] sStatus = Encoding.UTF8.GetBytes(Status);

                byte[] sTtl = new byte[sData.Length + sStatus.Length + 2];

                Buffer.BlockCopy(sData, 0, sTtl, 0, sData.Length);

                Buffer.BlockCopy(sStatus, 0, sTtl, sData.Length, sStatus.Length);

                TLVs.AddRange(Tools.MakeTLV(29, sTtl));
            }

            byte[] data = TLVs.ToArray();

            packet.Data = new byte[data.Length];

            Buffer.BlockCopy(data, 0, packet.Data, 0, data.Length);

            return packet;
        }
    }
}